package util

import (
	"context"
	"database/sql"
	"fmt"
)

type MysqlTable struct {
	Client *MysqlClient
	Name   string
}

func NewMysqlTable(client *MysqlClient, name string) *MysqlTable {
	return &MysqlTable{client, name}
}

func (mt *MysqlTable) Truncate(ctx context.Context) error {
	return mt.Client.Truncate(ctx, mt.Name)
}

func (mt *MysqlTable) Insert(ctx context.Context, row *MysqlRow) (int64, error) {
	return mt.Client.Insert(ctx, mt.Name, row)
}

func (mt *MysqlTable) InsertIgnore(ctx context.Context, row *MysqlRow) (int64, error) {
	return mt.Client.InsertIgnore(ctx, mt.Name, row)
}

func (mt *MysqlTable) InsertReplace(ctx context.Context, row *MysqlRow) (int64, error) {
	return mt.Client.InsertReplace(ctx, mt.Name, row)
}

func (mt *MysqlTable) InsertDuplicate(ctx context.Context, row *MysqlRow) (int64, error) {
	return mt.Client.InsertDuplicate(ctx, mt.Name, row)
}

func (mt *MysqlTable) InsertBatch(ctx context.Context, rows []*MysqlRow) (int64, error) {
	return mt.Client.InsertBatch(ctx, mt.Name, rows)
}

func (mt *MysqlTable) ShowColumns(ctx context.Context) (map[string]string, error) {
	return mt.Client.ShowColumns(ctx, mt.Name)
}

func (mt *MysqlTable) Count(ctx context.Context, query string, params ...any) (cnt int64, err error) {
	return mt.Client.Count(ctx, query, params...)
}

func (mt *MysqlTable) Select(ctx context.Context, query string, params ...any) ([]*MysqlRow, error) {
	return mt.Client.Select(ctx, query, params...)
}

func (mt *MysqlTable) SelectWalk(ctx context.Context, fn func(ctx context.Context, row *MysqlRow) error, query string, params ...any) error {
	return mt.Client.SelectWalk(ctx, fn, query, params...)
}

func (mt *MysqlTable) SelectPage(
	ctx context.Context,
	fn func(ctx context.Context, row *MysqlRow) error,
	page, size int64,
	where, order, cols string,
	params ...any,
) (totalRows, totalPages, currentPage int64, err error) {
	return mt.Client.SelectPage(ctx, fn, page, size, mt.Name, where, order, cols, params...)
}

func (mt *MysqlTable) GetOne(ctx context.Context, id any) (*MysqlRow, error) {
	var ret *MysqlRow
	err := mt.Client.SelectByIds(ctx, func(_ context.Context, row *MysqlRow) error {
		ret = row
		return nil
	}, mt.Name, "*", id)
	return ret, err
}

func (mt *MysqlTable) IdsWalk(
	ctx context.Context,
	fn func(ctx context.Context, row *MysqlRow) error,
	cols string,
	ids ...any,
) error {
	return mt.Client.SelectByIds(ctx, fn, mt.Name, cols, ids...)
}

func (mt *MysqlTable) AllWalk(ctx context.Context, fn func(ctx context.Context, row *MysqlRow) error, cols string) error {
	return mt.Client.SelectWalk(ctx, fn, fmt.Sprintf("SELECT %s FROM `%s` WHERE 1 = 1", cols, mt.Name))
}

func (mt *MysqlTable) Update(ctx context.Context, query string, params ...any) (int64, error) {
	return mt.Client.Update(ctx, query, params...)
}

func (mt *MysqlTable) UpdateById(ctx context.Context, row *MysqlRow, id any) (int64, error) {
	return mt.Client.UpdateById(ctx, mt.Name, row, id)
}

func (mt *MysqlTable) Delete(ctx context.Context, query string, params ...any) (int64, error) {
	return mt.Client.Delete(ctx, query, params...)
}

func (mt *MysqlTable) DeleteByIds(ctx context.Context, ids ...any) (int64, error) {
	return mt.Client.DeleteByIds(ctx, mt.Name, ids...)
}

func (mt *MysqlTable) Transaction(
	ctx context.Context,
	fn func(ctx context.Context, tx *sql.Tx) error,
	opts *sql.TxOptions,
) error {
	return mt.Client.Transaction(ctx, fn, opts)
}
